package com.common.www.service.auth;

import org.springframework.boot.base.jpa.service.BaseService;
import com.common.www.bean.entity.auth.AuthAccess;
import com.common.www.bean.entity.auth.AuthRole;
import com.common.www.bean.entity.auth.AuthUser;
import com.common.www.bean.vo.RoleVO;
import com.common.www.bean.vo.UserVo;
import com.common.www.config.WebConfig;
import com.common.www.redis.RedisConstant;
import com.common.www.repository.auth.UserRepository;
import com.common.www.service.redis.RedisTemplateService;
import com.common.www.utils.FormatUtils;
import com.common.www.utils.GlobalSessionUtils;
import com.common.www.utils.JwtUtils;
import com.common.www.utils.TxtUtil;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpSession;

import static com.common.www.utils.JwtUtils.TOKEN_EXP_MS;

@Service
@Transactional
public class UserService extends BaseService<AuthUser, String> {

    @Autowired
    private UserRepository repository;
    @Autowired
    private RoleService roleService;
    @Autowired
    private AccessService accessService;
    @Autowired
    TokenService tokenService;
    @Autowired
    RedisTemplateService redisTemplateService;

    @Override
    public UserRepository getRepository() {
        return repository;
    }

    public AuthUser findByUsername(String username) {
        Map<String, Object> map = new HashMap<>();
        map.put("username", username);
        map.put("flag", 1);
        List<AuthUser> list = queryToList(map, null);
        AuthUser authUser = null;
        if (list != null && list.size() > 0) {
            authUser = list.get(0);
        }
//        User user = repository.getByUsername(username);//逻辑删除查询使用统一入口
        return authUser;
    }

    public AuthUser findByPhoneNumber(String phoneNumber) {
//        User user = repository.getByPhoneNumber(phoneNumber);
        Map<String, Object> map = new HashMap<>();
        map.put("phone", phoneNumber);
        map.put("flag", 1);
        List<AuthUser> list = queryToList(map, null);
        AuthUser authUser = null;
        if (list != null && list.size() > 0) {
            authUser = list.get(0);
        }
        return authUser;
    }

    public AuthUser getById(String id) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        map.put("flag", 1);
        List<AuthUser> list = queryToList(map, null);
        AuthUser authUser = null;
        if (list != null && list.size() > 0) {
            authUser = list.get(0);
        }
        return authUser;
    }

    /**
     * 逻辑查询
     */
    public List<AuthUser> getList(Map<String, Object> map, Pageable pageable) {
        if (map == null)
            map = new HashMap<>();
        map.put("flag", 1);
        List<AuthUser> list = queryToList(map, pageable);
        return list;
    }

    /**
     * 逻辑查询
     */
    public Page<AuthUser> getListPage(Map<String, Object> map, Pageable pageable) {
        if (map == null)
            map = new HashMap<>();
        map.put("flag", 1);
        Page<AuthUser> page = query(map, pageable);
        return page;
    }

    /**
     * 该用户是否还可用
     */
    public boolean isAvailable(String id) {
        String sql = "select count(id) count from auth_user where id=? and locked=0 and flag=1";
        List<HashMap> sqlQuery = getRepository().executeSqlQuery(sql, new Object[]{id}, HashMap.class);
        int count = 0;
        if (sqlQuery != null && sqlQuery.size() > 0) {
            count = TxtUtil.getInteger(sqlQuery.get(0).get("count") + "");
            if (count > 0) {
                return true;
            } else {
                return false;
            }
        }
        return false;
//        AuthUser authUser = getById(id);
//        if (authUser.getLocked() || authUser.getFlag() == 0) {
//            return false;
//        }
//        return true;
    }

    /**
     * 退出登录
     */
    public void exitLogin(String token) {
        if (TxtUtil.isEmpty(GlobalSessionUtils.getToken())) {
            token = GlobalSessionUtils.getToken();
        }
        GlobalSessionUtils.getSession().setAttribute(WebConfig.ACCOUNT_KEY, null);


        redisTemplateService.delete(RedisConstant.REDIS_TOKEN_DIR + ":" + token);
    }

    /**
     * 把用户对象转换为可以封装的vo对象避免查询深度过深
     */
    public UserVo userToVo(AuthUser authUser) {
        UserVo userVo = new UserVo();

        List<AuthRole> authRoles = authUser.getAuthRoles();
        List<RoleVO> roleVOS = new ArrayList<>(0);
        BeanUtils.copyProperties(authUser, userVo);
        List<String> accessList = new ArrayList<>();

        if (authRoles != null) {
            for (AuthRole authRole :
                    authRoles) {
                RoleVO roleVo = RoleVO.builder().build();
                BeanUtils.copyProperties(authRole, roleVo);
                List<AuthAccess> authAccesses = authRole.getAuthAccesses();
                List<String> strings = new ArrayList<>();

                if (authAccesses != null)
                    authAccesses.forEach(access -> {
                        if (!strings.contains(access.getName()))
                            strings.add(access.getName());
                    });
                roleVo.setAccessList(strings);
                accessList.addAll(strings);
                roleVOS.add(roleVo);
            }
            userVo.setRoleVOS(roleVOS);
        }
        userVo.setAccessList(accessList);
        return userVo;
    }

    /**
     * 把用户登录情况放入session
     */
    public UserVo addUserToSession(UserVo userVo) {
        String token = JwtUtils.getToken(userVo.getId() + "");
        userVo.setToken(token);

        HttpSession session = GlobalSessionUtils.getSession();
        if (session != null) {
            session.setMaxInactiveInterval(TOKEN_EXP_MS / 1000);
            session.setAttribute(WebConfig.ACCOUNT_KEY, token);
        }
        redisTemplateService.set(RedisConstant.REDIS_TOKEN_DIR + ":" + userVo.getToken(), userVo, TOKEN_EXP_MS, TimeUnit.MILLISECONDS);
        return userVo;
    }

    /**
     * 是否有这个用户名
     */
    public boolean isHadUsername(String username) {
        String sql = "select count(id) count from auth_user where username=?";
        List<HashMap> sqlQuery = getRepository().executeSqlQuery(sql, new Object[]{username}, HashMap.class);
        int count = 0;
        if (sqlQuery != null && sqlQuery.size() > 0) {
            count = TxtUtil.getInteger(sqlQuery.get(0).get("count") + "");
        }
        return count > 0;
    }

    /**
     * 是否有这个用户名
     */
    public boolean isHadPhone(String phone) {
        String sql = "select count(id) count from auth_user where phone=?";
        List<HashMap> sqlQuery = getRepository().executeSqlQuery(sql, new Object[]{phone}, HashMap.class);
        int count = 0;
        if (sqlQuery != null && sqlQuery.size() > 0) {
            count = TxtUtil.getInteger(sqlQuery.get(0).get("count") + "");
        }
        return count > 0;
    }

    /**
     * 根据第三方平台的id来登录
     */
    public AuthUser findByPhone(String phone) {
        Map<String, Object> map = new HashMap<>();
        map.put("phone", phone);
        List<AuthUser> list = queryToList(map, null);
        AuthUser authUser = null;
        if (list != null && list.size() > 0) {
            authUser = list.get(0);
        }
//        User user = repository.getByUsername(username);//逻辑删除查询使用统一入口
        return authUser;
    }
    /**
     * 根据第三方平台的id来登录
     */
    public AuthUser findByMiniOpenId(String openId) {
        Map<String, Object> map = new HashMap<>();
        map.put("openId", openId);
        List<AuthUser> list = queryToList(map, null);
        AuthUser authUser = null;
        if (list != null && list.size() > 0) {
            authUser = list.get(0);
        }
//        User user = repository.getByUsername(username);//逻辑删除查询使用统一入口
        return authUser;
    }

    /**
     * 根据第三方平台的id来登录
     */
    public AuthUser findByAPPOpenId(String appOpenId) {
        Map<String, Object> map = new HashMap<>();
        map.put("appOpenId", appOpenId);
        List<AuthUser> list = queryToList(map, null);
        AuthUser authUser = null;
        if (list != null && list.size() > 0) {
            authUser = list.get(0);
        }
//        User user = repository.getByUsername(username);//逻辑删除查询使用统一入口
        return authUser;
    }

    /**
     * 根据第三方平台的联合id来登录
     */
    public AuthUser findByUnionid(String unionid) {
        Map<String, Object> map = new HashMap<>();
        map.put("unionid", unionid);
        List<AuthUser> list = queryToList(map, null);
        AuthUser authUser = null;
        if (list != null && list.size() > 0) {
            authUser = list.get(0);
        }
//        User user = repository.getByUsername(username);//逻辑删除查询使用统一入口
        return authUser;
    }


    /**
     * 从redis中查询出来用户对象
     */
    public UserVo getUserVoFromRedis(String token) {
        UserVo userVo = redisTemplateService.get(RedisConstant.REDIS_TOKEN_DIR + ":" + token, UserVo.class);
        return userVo;
    }


    /**
     * 查询用户存储的剩余时间
     */
    public void updateRedisUserExpireTime(String token) {
        long time = redisTemplateService.getExpire(RedisConstant.REDIS_TOKEN_DIR + ":" + token, TimeUnit.MILLISECONDS);
        if (time == -2) {//key不存在
            return;
        }

        if (TOKEN_EXP_MS - time > 60 * 60 * 1000) {//超过一小时则更新redis 的存储时间避免过期也避免浪费性能每次都查询
            redisTemplateService.expire(RedisConstant.REDIS_TOKEN_DIR + ":" + token, TOKEN_EXP_MS, TimeUnit.MILLISECONDS);
        }
    }

    /**
     * 获取用户的项目id集合
     */
    public Long[]  getUserProjectIdList(AuthUser authUser){
        if(StringUtils.isEmpty(authUser.getProjectIds())){
            return null;
        }else{
            List<String> projectIdList =  FormatUtils.getFormatList(authUser.getProjectIds());
            Long[] projectIds = new Long[projectIdList.size()];
            for(int i=0;i<projectIdList.size();i++){
                projectIds[i]=Long.parseLong(projectIdList.get(i));
            }
            return projectIds;
        }
    }



}